/**
 * @file asdu_assembler.h
 * @brief ASDU组装器头文件
 * @details 本文件定义了104协议的ASDU组装器接口，包括通用ASDU组装、遥信数据ASDU
 *          组装、遥测数据ASDU组装、控制命令ASDU组装、系统命令ASDU组装等核心功能。
 *          支持多种数据类型的信息对象组装，确保生成的ASDU数据符合104协议规范。
 * 
 * @author zyb
 * @date 2025-10-07
 * @version 1.0
 * 
 * @note ASDU组装时需要确保信息对象数量在有效范围内（1-127）
 * @warning 不同类型的信息对象需要对应正确的类型标识
 * 
 * @see asdu_assembler.c
 * @see protocol_types.h
 * @see constants.h
 * @see error_codes.h
 */

#ifndef ASDU_ASSEMBLER_H
#define ASDU_ASSEMBLER_H

#include "protocol_types.h"

#ifdef __cplusplus
extern "C" {
#endif

/* ==================== 通用ASDU组装函数 ==================== */

/**
 * @brief 组装通用ASDU
 * @details 将ASDU结构体组装成字节流格式。ASDU包含类型标识、可变结构限定词、
 *          传送原因、公共地址、信息对象地址和信息对象数据等字段。
 *          函数会验证ASDU格式和缓冲区大小，然后将ASDU数据写入缓冲区。
 * 
 * @param asdu ASDU结构指针，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小，必须至少为ASDU_HEADER_SIZE
 * @param actual_size 实际写入的字节数输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 组装成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_ASDU_INVALID_TYPE: 无效ASDU类型
 *         - PROTOCOL_ERROR_ASDU_INVALID: ASDU无效
 * 
 * @note 组装后的数据可以直接用于APDU传输
 * @warning 缓冲区必须足够大以容纳完整的ASDU数据
 * 
 * @see asdu_t
 * @see validate_asdu
 * @see ASDU_HEADER_SIZE
 */
protocol_error_t assemble_asdu(const asdu_t* asdu, uint8_t* buffer, size_t buffer_size, size_t* actual_size);

/* ==================== 遥信数据ASDU组装函数 ==================== */

/**
 * @brief 组装单点信息ASDU
 * @details 组装单点信息ASDU，包括M_SP_NA_1、M_SP_TA_1、M_SP_TB_1等类型。
 *          函数会根据类型标识组装相应的ASDU格式，包含信息对象地址和单点信息数据。
 * 
 * @param type_id 类型标识，如M_SP_NA_1、M_SP_TA_1、M_SP_TB_1
 * @param cot 传送原因
 * @param common_addr 公共地址
 * @param info_objects 单点信息对象数组，不能为NULL
 * @param count 信息对象数量，范围1-127
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_size 实际写入的字节数输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 组装成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 信息对象数量必须在1-127范围内
 * @warning 不同类型标识对应不同的ASDU格式
 * 
 * @see single_point_info_t
 * @see type_id_t
 * @see cause_of_transmission_t
 */
protocol_error_t assemble_single_point_asdu(type_id_t type_id, 
                                           cause_of_transmission_t cot,
                                           asdu_common_address_t common_addr,
                                           const single_point_info_t* info_objects,
                                           uint8_t count,
                                           uint8_t* buffer,
                                           size_t buffer_size,
                                           size_t* actual_size);

/**
 * @brief 组装双点信息ASDU
 * @details 组装双点信息ASDU，包括M_DP_NA_1、M_DP_TA_1、M_DP_TB_1等类型。
 *          函数会根据类型标识组装相应的ASDU格式，包含信息对象地址和双点信息数据。
 * 
 * @param type_id 类型标识，如M_DP_NA_1、M_DP_TA_1、M_DP_TB_1
 * @param cot 传送原因
 * @param common_addr 公共地址
 * @param info_objects 双点信息对象数组，不能为NULL
 * @param count 信息对象数量，范围1-127
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_size 实际写入的字节数输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 组装成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 信息对象数量必须在1-127范围内
 * @warning 不同类型标识对应不同的ASDU格式
 * 
 * @see double_point_info_t
 * @see type_id_t
 * @see cause_of_transmission_t
 */
protocol_error_t assemble_double_point_asdu(type_id_t type_id, 
                                           cause_of_transmission_t cot,
                                           asdu_common_address_t common_addr,
                                           const double_point_info_t* info_objects,
                                           uint8_t count,
                                           uint8_t* buffer,
                                           size_t buffer_size,
                                           size_t* actual_size);

/* ==================== 遥测数据ASDU组装函数 ==================== */

/**
 * @brief 组装测量值ASDU
 * @details 组装测量值ASDU，包括M_ME_NA_1、M_ME_NB_1、M_ME_NC_1等类型。
 *          函数会根据类型标识组装相应的ASDU格式，包含信息对象地址和测量值数据。
 * 
 * @param type_id 类型标识，如M_ME_NA_1、M_ME_NB_1、M_ME_NC_1
 * @param cot 传送原因
 * @param common_addr 公共地址
 * @param info_objects 测量值对象数组，不能为NULL
 * @param count 信息对象数量，范围1-127
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_size 实际写入的字节数输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 组装成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 信息对象数量必须在1-127范围内
 * @warning 不同类型标识对应不同的测量值格式
 * 
 * @see measurement_value_t
 * @see type_id_t
 * @see cause_of_transmission_t
 */
protocol_error_t assemble_measurement_asdu(type_id_t type_id, 
                                          cause_of_transmission_t cot,
                                          asdu_common_address_t common_addr,
                                          const measurement_info_t* info_objects,
                                          uint8_t count,
                                          uint8_t* buffer,
                                          size_t buffer_size,
                                          size_t* actual_size);

/* ==================== 控制命令ASDU组装函数 ==================== */

/**
 * @brief 组装单点命令ASDU
 * @details 组装单点命令ASDU，包括C_SC_NA_1、C_SC_TA_1等类型。
 *          函数会根据类型标识组装相应的ASDU格式，包含信息对象地址和单点命令数据。
 * 
 * @param cot 传送原因
 * @param common_addr 公共地址
 * @param info_objects 单点命令对象数组，不能为NULL
 * @param count 信息对象数量，范围1-127
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_size 实际写入的字节数输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 组装成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 信息对象数量必须在1-127范围内
 * @warning 单点命令用于遥控操作
 * 
 * @see single_command_t
 * @see cause_of_transmission_t
 */
protocol_error_t assemble_single_command_asdu(cause_of_transmission_t cot,
                                             asdu_common_address_t common_addr,
                                             const single_command_info_t* info_objects,
                                             uint8_t count,
                                             uint8_t* buffer,
                                             size_t buffer_size,
                                             size_t* actual_size);

/**
 * @brief 组装双点命令ASDU
 * @details 组装双点命令ASDU，包括C_DC_NA_1、C_DC_TA_1等类型。
 *          函数会根据类型标识组装相应的ASDU格式，包含信息对象地址和双点命令数据。
 * 
 * @param cot 传送原因
 * @param common_addr 公共地址
 * @param info_objects 双点命令对象数组，不能为NULL
 * @param count 信息对象数量，范围1-127
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_size 实际写入的字节数输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 组装成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 信息对象数量必须在1-127范围内
 * @warning 双点命令用于遥控操作
 * 
 * @see double_command_t
 * @see cause_of_transmission_t
 */
protocol_error_t assemble_double_command_asdu(cause_of_transmission_t cot,
                                             asdu_common_address_t common_addr,
                                             const double_command_info_t* info_objects,
                                             uint8_t count,
                                             uint8_t* buffer,
                                             size_t buffer_size,
                                             size_t* actual_size);

/* ==================== 系统命令ASDU组装函数 ==================== */

/**
 * @brief 组装总召唤命令ASDU
 * @details 组装总召唤命令ASDU (C_IC_NA_1)，用于请求所有数据。
 *          函数会组装包含召唤限定词的ASDU格式。
 * 
 * @param common_addr 公共地址
 * @param qoi 召唤限定词
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_size 实际写入的字节数输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 组装成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 总召唤命令用于请求所有数据
 * @warning 召唤限定词必须有效
 * 
 * @see qoi_t
 * @see asdu_common_address_t
 */
protocol_error_t assemble_total_interrogation_asdu(asdu_common_address_t common_addr,
                                                  qoi_t qoi,
                                                  uint8_t* buffer,
                                                  size_t buffer_size,
                                                  size_t* actual_size);

/**
 * @brief 组装时钟同步命令ASDU
 * @details 组装时钟同步命令ASDU (C_CS_NA_1)，用于时钟同步。
 *          函数会组装包含时间戳的ASDU格式。
 * 
 * @param common_addr 公共地址
 * @param time 时间戳，不能为NULL
 * @param buffer 输出缓冲区，不能为NULL
 * @param buffer_size 缓冲区大小
 * @param actual_size 实际写入的字节数输出，不能为NULL
 * @return 协议错误码
 *         - PROTOCOL_SUCCESS: 组装成功
 *         - PROTOCOL_ERROR_NULL_POINTER: 空指针错误
 *         - PROTOCOL_ERROR_BUFFER_TOO_SMALL: 缓冲区太小
 *         - PROTOCOL_ERROR_INVALID_PARAM: 无效参数
 * 
 * @note 时钟同步命令用于时间同步
 * @warning 时间戳必须有效
 * 
 * @see cp56time2a_t
 * @see asdu_common_address_t
 */
protocol_error_t assemble_clock_sync_asdu(asdu_common_address_t common_addr,
                                         const cp56time2a_t* time,
                                         uint8_t* buffer,
                                         size_t buffer_size,
                                         size_t* actual_size);

#ifdef __cplusplus
}
#endif

#endif /* ASDU_ASSEMBLER_H */
